// 
//  Copyright (C) 2009 Jacek Trubłajewicz
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 

using System;
using System.Drawing;
using System.Collections.Generic;
using System.IO;
using Mono.Unix;
using NLog;

namespace wxGadu
{
	
	public class HistoryFrame : wx.Frame
	{
		#region Id
		public enum Id
		{
			closeButton = 6763,
			deleteMenu,
			saveMenu
		}
		#endregion
		
		#region windows
		private wx.SplitterWindow splitterWindow;
		private HistoryChatPanel chatPanel;
		private HistoryTreePanel treePanel;
		#endregion
		
		#region controls
		private wx.Button closeButton;
		private wx.Menu menu;
		#endregion
		
		#region data members
		private HistoryManager historyManager;
		private MainFrame mainFrame;
		private Dispatcher dispatcher;
		private Dictionary<int, Dictionary<string, string>> chats;
		private wx.TreeItemId rootId;
		#endregion
		private FileStream fs;
		private StreamWriter sw;
#if LOG
		private Logger logger = LogManager.GetCurrentClassLogger();
#endif
		
		public HistoryFrame(wx.Window parent, int id, string title, Point pos, Size size, uint style): 
			base(parent, id, title, pos, size, style)
		{
			mainFrame = (MainFrame) parent;
			dispatcher = mainFrame.Dispatch;
			historyManager = dispatcher.HistoryMgr;
			
			chats = new Dictionary<int, Dictionary<string, string>>();
			
			DoControls();
			DoLayout();
			this.CenterOnScreen();
			
//			EVT_UPDATE_UI((int) FakeId.fillHistoryTree, new wx.EventListener(FillTree));
			EVT_MENU((int) Id.deleteMenu, new wx.EventListener(OnDeleteMenu));
			EVT_MENU((int) Id.saveMenu, new wx.EventListener(OnSaveMenu));
			EVT_BUTTON((int) Id.closeButton, new wx.EventListener(OnCloseButton));
			EVT_UPDATE_UI((int) Id.saveMenu, new wx.EventListener(OnSaveMenuUpdate));
			EVT_UPDATE_UI((int) Id.deleteMenu, new wx.EventListener(OnDeleteMenuUpdate));
			EVT_CLOSE(new wx.EventListener(OnFrameClose));
			
			FillTree();
		}
		
		private void DoControls()
		{
			splitterWindow = new wx.SplitterWindow(this);
			chatPanel = new HistoryChatPanel(splitterWindow);
			treePanel = new HistoryTreePanel(splitterWindow);
			
			splitterWindow.SashGravity = 0.1;
			splitterWindow.MinimumPaneSize = 50;
			splitterWindow.SplitVertically(treePanel, chatPanel);
			
			closeButton = new wx.Button(this, (int) Id.closeButton, Catalog.GetString("Close"));
			
			wx.Menu menu = new wx.Menu();
			wx.MenuItem delete = new wx.MenuItem(menu, (int) Id.deleteMenu, Catalog.GetString("Delete"));
			delete.Bitmap = dispatcher.MainWindow.ImageMgr[ImageManager.DELETE_CONTACT];
			menu.Append(delete);
			wx.MenuItem save = new wx.MenuItem(menu, (int) Id.saveMenu, Catalog.GetString("Save as HTML"));
			save.Bitmap = dispatcher.MainWindow.ImageMgr[ImageManager.SAVE_AS];
			menu.Append(save);
						
			wx.MenuBar menuBar = new wx.MenuBar();
			menuBar.Append(menu, Catalog.GetString("Actions"));
			this.MenuBar = menuBar;
			wx.Icon icon = new wx.Icon();
			icon.CopyFromBitmap(mainFrame.ImageMgr[ImageManager.HISTORY]);
			this.Icon = icon;
		}
		
		private void DoLayout()
		{
			wx.BoxSizer topSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
			{
				topSizer.Add(splitterWindow, 1, wx.Stretch.wxEXPAND|wx.Direction.wxALL, 5);
				
				wx.BoxSizer buttonSizer = new wx.BoxSizer(wx.Orientation.wxHORIZONTAL);
				{
					buttonSizer.Add(20, 20, 1, 0, 0);
					buttonSizer.Add(closeButton, 0, wx.Direction.wxALL, 5);
				}
				topSizer.Add(buttonSizer, 0, wx.Stretch.wxEXPAND);
			}
			topSizer.Fit(this);
			topSizer.SetSizeHints(this);
			this.Sizer = topSizer;
		}
		
		private void FillTree()
		{
			rootId =  treePanel.ContactsTree.AddRoot(Catalog.GetString("History"), 0, 0, new HistoryTreeItemData());
			
			HistoryTreeItemData[] dirs = historyManager.GetContactsHistory();
			foreach (HistoryTreeItemData treeItem in dirs)
			{
				treePanel.ContactsTree.AppendItem(rootId, treeItem.Name + " [" + treeItem.Uin + "]", 1, 1, treeItem);
			}
			treePanel.ContactsTree.SortChildren(treePanel.ContactsTree.RootItem);
		}
		
		private void OnFrameClose(object sender, wx.Event evt)
		{
			mainFrame.HistFrame = null;
			evt.Skip();
		}
		
		private void OnCloseButton(object sender, wx.Event evt)
		{
			this.Close();
		}
		
		private void OnSaveMenuUpdate(object sender, wx.Event evt)
		{
			wx.UpdateUIEvent updateEvt = (wx.UpdateUIEvent) evt;
			
			wx.TreeItemId itemId = treePanel.ContactsTree.Selection;
			if (itemId.IsOk())
			{
				HistoryTreeItemData itemData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(itemId);
				if (itemData.Uin != 0 && itemData.FilePath != string.Empty)
					updateEvt.Enabled = true;
				else
					updateEvt.Enabled = false;
			}
			else
			{
				updateEvt.Enabled = false;
			}
		}
			
		private void OnDeleteMenuUpdate(object sender, wx.Event evt)
		{
			wx.UpdateUIEvent updateEvt = (wx.UpdateUIEvent) evt;
			
			wx.TreeItemId itemId = treePanel.ContactsTree.Selection;
			if (itemId.IsOk())
			{
				HistoryTreeItemData itemData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(itemId);
				if (itemData.Uin != 0)
					updateEvt.Enabled = true;
				else
					updateEvt.Enabled = false;
			}
			else
			{
				updateEvt.Enabled = false;
			}
		}
		
		private void OnDeleteMenu(object sender, wx.Event evt)
		{
			wx.TreeItemId itemId = treePanel.ContactsTree.Selection;
			if (itemId.IsOk())
			{
				HistoryTreeItemData itemData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(itemId);
				
				// if selected is the whole contact
				if (itemData.FilePath == string.Empty)
				{
					wx.MessageDialog md = new wx.MessageDialog(this,
					                                           String.Format(Catalog.GetString("Do you realy want to delete all history files of: {0}?"), itemData.Name),
					                                           Catalog.GetString("Delete history"),
					                                           wx.MessageDialog.wxICON_QUESTION|wx.MessageDialog.wxYES_NO|
					                                           wx.MessageDialog.wxNO_DEFAULT);
					if (md.ShowModal() == wx.MessageDialog.wxID_YES)
					{
#if LOG
						logger.Trace(String.Format(Catalog.GetString("Deleting all history files of: {0}"), itemData.Name));
#endif
						string path = dispatcher.AppCfg.HistoryDir + Path.DirectorySeparatorChar + itemData.Uin;
						try
						{
							Directory.Delete(path, true);
						}
						catch (Exception e)
						{
#if LOG
							logger.ErrorException(String.Format(Catalog.GetString("Unable to delete history of: {0}"), itemData.Name), e);
#endif
							md = new wx.MessageDialog(this,
					                                           String.Format(Catalog.GetString("Unable to delete history of: {0}\n{1}"), itemData.Name, e.Message),
					                                           Catalog.GetString("Delete history"),
					                                           wx.MessageDialog.wxICON_ERROR);
							md.ShowModal();
							return;
						}
						
						// delete form tree
						treePanel.ContactsTree.DeleteChildren(itemId);
						treePanel.ContactsTree.Delete(itemId);
					}
				}
				else // if seleceted is only one chat
				{
					wx.MessageDialog md = new wx.MessageDialog(this,
					                                           String.Format(Catalog.GetString("Do you realy want to delete history file {0}?"), itemData.Name),
					                                           Catalog.GetString("Delete history"),
					                                           wx.MessageDialog.wxICON_QUESTION|wx.MessageDialog.wxYES_NO|
					                                           wx.MessageDialog.wxNO_DEFAULT);
					if (md.ShowModal() == wx.MessageDialog.wxID_YES)
					{
						try
						{
							File.Delete(itemData.FilePath);
						}
						catch (Exception e)
						{
#if LOG
							logger.ErrorException(String.Format(Catalog.GetString("Unable to delete history file: {0}"), itemData.Name), e);
#endif
							md = new wx.MessageDialog(this,
					                                           String.Format(Catalog.GetString("Unable to delete history file: {0}\n{1}"), itemData.Name, e.Message),
					                                           Catalog.GetString("Delete history"),
					                                           wx.MessageDialog.wxICON_ERROR);
							md.ShowModal();
							return;
						}
						
						// delete file from tree
						treePanel.ContactsTree.Delete(itemId);
					}
				}
			}
		}
		
		private void OnSaveMenu(object sender, wx.Event evt)
		{
			wx.TreeItemId itemId = treePanel.ContactsTree.Selection;
			if (itemId.IsOk())
			{
				HistoryTreeItemData itemData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(itemId);
				
				if (chats.ContainsKey(itemData.Uin))
				{
					// check if chat is already loaded in cache
					if (chats[itemData.Uin].ContainsKey(itemData.Name))
						chatPanel.SetNewPage(chats[itemData.Uin][itemData.Name]);
					else // load chat and put it in cache
					{
						string chatHtmlCode = historyManager.GetChatHtmlCode(itemData.FilePath);
						chatPanel.SetNewPage(chatHtmlCode);
						chats[itemData.Uin].Add(itemData.Name, chatHtmlCode);
					}	
				}
				else
				{
					chats.Add(itemData.Uin, new Dictionary<string, string>());
					string chatHtmlCode = historyManager.GetChatHtmlCode(itemData.FilePath);
					chatPanel.SetNewPage(chatHtmlCode);
					chats[itemData.Uin].Add(itemData.Name, chatHtmlCode);
				}
				
				string savePath;
				wx.FileDialog saveDlg = new wx.FileDialog(this, Catalog.GetString("Save file"), 
				                                          Environment.GetFolderPath(Environment.SpecialFolder.Personal),
				                                          itemData.Name + ".html",
				                                          "HTML Files (*.html)|*.html",
				                                          wx.FileDialogStyle.wxSAVE|wx.FileDialogStyle.wxOVERWRITE_PROMPT);
				
				if (saveDlg.ShowModal() == wx.FileDialog.wxID_OK)
				{
					savePath = saveDlg.Path;
					try
					{
						fs = new FileStream(savePath, FileMode.Create, FileAccess.Write);
						sw = new StreamWriter(fs);
						
						sw.WriteLine(chats[itemData.Uin][itemData.Name]);
#if LOG
						logger.Trace(String.Format(Catalog.GetString("History file: {0} saved successfuly to: {1}"), itemData.Name, savePath));
#endif
					}
					catch (Exception e)
					{
#if LOG
						logger.ErrorException(String.Format(Catalog.GetString("Unable to save history file: {0}"), itemData.Name), e);
#endif
						wx.MessageDialog md = new wx.MessageDialog(this,
				                                           String.Format(Catalog.GetString("Unable to save history file: {0}\n{1}"), itemData.Name, e.Message),
				                                           Catalog.GetString("Save history"),
				                                           wx.MessageDialog.wxICON_ERROR);
						md.ShowModal();						
					}
					finally
					{
						if (sw != null)
						{
							sw.Close();
							sw = null;
						}
						if (fs != null)
						{
							fs.Close();
							fs = null; 
						}
					}
				}
			}
		}
		
		/// <summary>
		/// Searches through tree and expands history of given <c>uin</c>
		/// </summary>
		/// <param name="uin">
		/// A <see cref="System.Int32"/>
		/// </param>
		public void ExpandContactHistory(int uin)
		{
			wx.TreeItemId rootId = treePanel.ContactsTree.RootItem;
			IntPtr cookie = new IntPtr(999);
			wx.TreeItemId firstId = treePanel.ContactsTree.GetFirstChild(rootId, ref cookie);
			HistoryTreeItemData firstData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(firstId);

			if (firstData.Uin == uin)
			{
				treePanel.ContactsTree.SelectItem(firstId);
				OnTreeItemAcitvated(this, null);
				return;
			}
			
			wx.TreeItemId nextId;
			HistoryTreeItemData nextData;
			while ((nextId = treePanel.ContactsTree.GetNextChild(rootId, ref cookie)).IsOk() == true)
			{
				nextData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(nextId);
				if (nextData.Uin == uin)
				{
					treePanel.ContactsTree.SelectItem(nextId);
					OnTreeItemAcitvated(this, null);
					return;
				}
			}
			
			// we get here so there is no history connected to this UIN
#if LOG
			logger.Trace(String.Format(Catalog.GetString("There is no history connected with UIN: {0}"), uin));
#endif
			dispatcher.MainWindow.HistoryErrorMessageDialog(
				                                                String.Format(
				                                                              Catalog.GetString("There is no history connected with UIN: {0}"), uin));
		}
		
		public void OnTreeItemAcitvated(object sender, wx.Event evt)
		{
			wx.TreeItemId itemId = treePanel.ContactsTree.Selection;
			HistoryTreeItemData itemData = (HistoryTreeItemData) treePanel.ContactsTree.GetItemData(itemId);
			// if root was activated only expand it
//			if (itemId == rootId)
//				return;
			if (itemData.Uin == 0)
			{
				treePanel.ContactsTree.Expand(itemId);
				return;
			}
			
			if (itemData.FilePath == string.Empty)
			{
				if (treePanel.ContactsTree.GetChildrenCount(itemId) > 0)
					treePanel.ContactsTree.DeleteChildren(itemId);
				
				string path = dispatcher.AppCfg.HistoryDir + Path.DirectorySeparatorChar + itemData.Uin.ToString();
				FileInfo[] files;
				try
				{
					DirectoryInfo contactDir = new DirectoryInfo(path);
					files = contactDir.GetFiles();
					
					foreach (FileInfo file in files)
					{
						HistoryTreeItemData newItem = new HistoryTreeItemData();
						newItem.FilePath = file.FullName;
						newItem.Name = file.Name;
						newItem.Uin = itemData.Uin;
						
						treePanel.ContactsTree.AppendItem(itemId, newItem.Name, 2, 2, newItem);
					}
					
					treePanel.ContactsTree.Expand(itemId);
				}
				catch (Exception e)
				{
#if LOG
					logger.ErrorException(String.Format(Catalog.GetString("Can't read directory content: {0}"), path), e);
#endif
					dispatcher.MainWindow.HistoryErrorMessageDialog(
				                                                String.Format(
				                                                              Catalog.GetString("Can't read directory content: {0}\n{1}"), path, e));
				}
			}
			else // this is leaf
			{
				if (chats.ContainsKey(itemData.Uin))
				{
					// check if chat is already loaded in cache
					if (chats[itemData.Uin].ContainsKey(itemData.Name))
						chatPanel.SetNewPage(chats[itemData.Uin][itemData.Name]);
					else // load chat and put it in cache
					{
						string chatHtmlCode = historyManager.GetChatHtmlCode(itemData.FilePath);
						chatPanel.SetNewPage(chatHtmlCode);
						chats[itemData.Uin].Add(itemData.Name, chatHtmlCode);
					}	
				}
				else
				{
					chats.Add(itemData.Uin, new Dictionary<string, string>());
					string chatHtmlCode = historyManager.GetChatHtmlCode(itemData.FilePath);
					chatPanel.SetNewPage(chatHtmlCode);
					chats[itemData.Uin].Add(itemData.Name, chatHtmlCode);
				}
			}
		}
		
		public void OnTreeItemExpanded(object sender, wx.Event evt)
		{
			
		}
		
		public MainFrame MainFrame
		{
			get { return mainFrame; }
		}
	}
}
